package com.tobeface.wechat.request.api;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.tobeface.modules.lang.Function;
import com.tobeface.modules.lang.Langs;
import com.tobeface.modules.lang.Requires;
import com.tobeface.wechat.request.AbstractWeChatApiRequestBuilder;
import com.tobeface.wechat.request.WeChatRequest;

import java.util.List;
import java.util.Map;

/**
 * @author loudyn
 */
public class ServiceApiRequestBuilder extends AbstractWeChatApiRequestBuilder {

    private final Map<String, Object> payloads = Maps.newHashMap();

    /**
     *
     */
    public ServiceApiRequestBuilder() {
        super("https://api.weixin.qq.com/cgi-bin/message/custom/send", WeChatRequest.Verb.POST);
    }

    /**
     * @return
     */
    public TextServiceMessageBuilder sendText() {
        return new TextServiceMessageBuilder(this);
    }

    /**
     * @return
     */
    public ImageServiceMessageBuilder sendImage() {
        return new ImageServiceMessageBuilder(this);
    }

    /**
     * @return
     */
    public VoiceServiceMessageBuilder sendVoice() {
        return new VoiceServiceMessageBuilder(this);
    }

    /**
     * @return
     */
    public VideoServiceMessageBuilder sendVideo() {
        return new VideoServiceMessageBuilder(this);
    }

    /**
     * @return
     */
    public MusicServiceMessageBuilder sendMusic() {
        return new MusicServiceMessageBuilder(this);
    }

    /**
     * @return
     */
    public NewsServiceMessageBuilder sendNews() {
        return new NewsServiceMessageBuilder(this);
    }

    @Override
    protected void configRequest(WeChatRequest request) {
        request.entity(payloads);
    }

    public class TextServiceMessageBuilder {

        final ServiceApiRequestBuilder parent;

        /**
         * @param parent
         */
        TextServiceMessageBuilder(ServiceApiRequestBuilder parent) {
            this.parent = parent;
        }

        /**
         * @param openId
         * @return
         */
        public TextServiceMessageBuilder to(String openId) {
            Requires.hasText(openId, "openId must not be null or empty!");
            parent.payloads.put("touser", openId);
            return this;
        }

        /**
         * @param content
         * @return
         */
        public TextServiceMessageBuilder content(String content) {
            Requires.hasText(content, "content must not be null or empty!");
            parent.payloads.put("text", ImmutableMap.of("content", content));
            return this;
        }

        /**
         * @return
         */
        public WeChatRequest build() {
            parent.payloads.put("msgtype", "text");
            return parent.build();
        }
    }

    public class ImageServiceMessageBuilder {

        final ServiceApiRequestBuilder parent;

        /**
         * @param parent
         */
        ImageServiceMessageBuilder(ServiceApiRequestBuilder parent) {
            this.parent = parent;
        }

        /**
         * @param openId
         * @return
         */
        public ImageServiceMessageBuilder to(String openId) {
            Requires.hasText(openId, "openId must not be null or empty!");
            parent.payloads.put("touser", openId);
            return this;
        }

        public ImageServiceMessageBuilder mediaId(String mediaId) {
            Requires.hasText(mediaId, "mediaId must not be null or empty!");
            parent.payloads.put("image", ImmutableMap.of("media_id", mediaId));
            return this;
        }

        /**
         * @return
         */
        public WeChatRequest build() {
            parent.payloads.put("msgtype", "image");
            return parent.build();
        }


    }

    public class VoiceServiceMessageBuilder {

        final ServiceApiRequestBuilder parent;

        /**
         * @param parent
         */
        VoiceServiceMessageBuilder(ServiceApiRequestBuilder parent) {
            this.parent = parent;
        }

        /**
         * @param openId
         * @return
         */
        public VoiceServiceMessageBuilder to(String openId) {
            Requires.hasText(openId, "openId must not be null or empty!");
            parent.payloads.put("touser", openId);
            return this;
        }

        public VoiceServiceMessageBuilder mediaId(String mediaId) {
            Requires.hasText(mediaId, "mediaId must not be null or empty!");
            parent.payloads.put("voice", ImmutableMap.of("media_id", mediaId));
            return this;
        }

        /**
         * @return
         */
        public WeChatRequest build() {
            parent.payloads.put("msgtype", "voice");
            return parent.build();
        }


    }

    public class VideoServiceMessageBuilder {

        final ServiceApiRequestBuilder parent;
        final Map<String, Object> props = Maps.newHashMap();

        /**
         * @param parent
         */
        VideoServiceMessageBuilder(ServiceApiRequestBuilder parent) {
            this.parent = parent;
        }

        /**
         * @param openId
         * @return
         */
        public VideoServiceMessageBuilder to(String openId) {
            Requires.hasText(openId, "openId must not be null or empty!");
            parent.payloads.put("touser", openId);
            return this;
        }

        public VideoServiceMessageBuilder mediaId(String mediaId) {
            Requires.hasText(mediaId, "mediaId must not be null or empty!");
            this.props.put("media_id", mediaId);
            return this;
        }

        public VideoServiceMessageBuilder title(String title) {
            Requires.hasText(title, "title must not be null or empty!");
            this.props.put("title", title);
            return this;
        }

        public VideoServiceMessageBuilder descr(String descr) {
            Requires.hasText(descr, "descr must not be null or empty!");
            this.props.put("description", descr);
            return this;
        }

        /**
         * @return
         */
        public WeChatRequest build() {
            parent.payloads.put("msgtype", "video");
            parent.payloads.put("video", props);
            return parent.build();
        }


    }

    public class MusicServiceMessageBuilder {

        final ServiceApiRequestBuilder parent;
        final Map<String, Object> props = Maps.newHashMap();

        /**
         * @param parent
         */
        MusicServiceMessageBuilder(ServiceApiRequestBuilder parent) {
            this.parent = parent;
        }

        /**
         * @param openId
         * @return
         */
        public MusicServiceMessageBuilder to(String openId) {
            Requires.hasText(openId, "openId must not be null or empty!");
            parent.payloads.put("touser", openId);
            return this;
        }

        public MusicServiceMessageBuilder url(String url) {
            Requires.hasText(url, "mediaId must not be null or empty!");
            this.props.put("musicurl", url);
            return this;
        }

        public MusicServiceMessageBuilder hqurl(String hqurl) {
            Requires.hasText(hqurl, "hqurl must not be null or empty!");
            this.props.put("hqmusicurl", hqurl);
            return this;
        }

        public MusicServiceMessageBuilder thumbMediaId(String thumbMediaId) {
            Requires.hasText(thumbMediaId, "thumbMediaId must not be null or empty!");
            this.props.put("thumb_media_id", thumbMediaId);
            return this;
        }

        public MusicServiceMessageBuilder title(String title) {
            Requires.hasText(title, "title must not be null or empty!");
            this.props.put("title", title);
            return this;
        }

        public MusicServiceMessageBuilder descr(String descr) {
            Requires.hasText(descr, "descr must not be null or empty!");
            this.props.put("description", descr);
            return this;
        }

        /**
         * @return
         */
        public WeChatRequest build() {
            parent.payloads.put("msgtype", "music");
            parent.payloads.put("music", props);
            return parent.build();
        }
    }


    public class NewsServiceMessageBuilder {

        static final int MAX_ITEMS = 10;
        final ServiceApiRequestBuilder parent;
        final List<NewsItemServiceMessageBuilder> items = Lists.newArrayList();

        /**
         * @param parent
         */
        NewsServiceMessageBuilder(ServiceApiRequestBuilder parent) {
            this.parent = parent;
        }

        /**
         * @param openId
         * @return
         */
        public NewsServiceMessageBuilder to(String openId) {
            Requires.hasText(openId, "openId must not be null or empty!");
            parent.payloads.put("touser", openId);
            return this;
        }

        /**
         * @return
         */
        public NewsItemServiceMessageBuilder item() {
            if (items.size() >= MAX_ITEMS) {
                throw new UnsupportedOperationException("News items over limit!");
            }

            NewsItemServiceMessageBuilder item = new NewsItemServiceMessageBuilder(this);
            items.add(item);
            return item;
        }

        /**
         * @return
         */
        public WeChatRequest build() {
            List<Map<String, Object>> itemProps = Langs.map(items, new Function<NewsItemServiceMessageBuilder, Map<String, Object>>() {
                @Override
                public Map<String, Object> apply(NewsItemServiceMessageBuilder itemBuilder) {
                    return itemBuilder.props;
                }
            });

            parent.payloads.put("msgtype", "news");
            parent.payloads.put("news", ImmutableMap.of("articles", itemProps));
            return parent.build();
        }
    }

    public class NewsItemServiceMessageBuilder {

        final NewsServiceMessageBuilder parent;
        final Map<String, Object> props = Maps.newHashMap();

        /**
         * @param parent
         */
        NewsItemServiceMessageBuilder(NewsServiceMessageBuilder parent) {
            this.parent = parent;
        }

        public NewsItemServiceMessageBuilder url(String url) {
            Requires.hasText(url, "mediaId must not be null or empty!");
            this.props.put("musicurl", url);
            return this;
        }

        public NewsItemServiceMessageBuilder picUrl(String picUrl) {
            Requires.hasText(picUrl, "picUrl must not be null or empty!");
            this.props.put("picurl", picUrl);
            return this;
        }

        public NewsItemServiceMessageBuilder title(String title) {
            Requires.hasText(title, "title must not be null or empty!");
            this.props.put("title", title);
            return this;
        }

        public NewsItemServiceMessageBuilder descr(String descr) {
            Requires.hasText(descr, "descr must not be null or empty!");
            this.props.put("description", descr);
            return this;
        }

        /**
         * @return
         */
        public NewsItemServiceMessageBuilder item() {
            return parent.item();
        }

        /**
         * @return
         */
        public WeChatRequest build() {
            return parent.build();
        }
    }


}
